#include "hint.h"

HugeInteger::HugeInteger (long long a)
{
    while (a)
    {
        push_back (a % base);
        a /= base;
    }
}

HugeInteger::HugeInteger (const string a)
{
    from_string (a.c_str ());
}

HugeInteger::HugeInteger (const char * a)
{
    from_string (a);
}

const HugeInteger 
HugeInteger::operator+ (const HugeInteger & a) const
{
    size_t big = size ();
    if (a.size () > big) big = a.size ();

    HugeInteger tmp;
    tmp.reserve (big);

    for (size_t i = 0; i < big; i++) {
        tmp.at (i) = a.at (i) + at (i);
    }

    return tmp;
}

const HugeInteger 
HugeInteger::operator- (const HugeInteger & a) const
{
    return HugeInteger (number () - a.number ());
}

const HugeInteger 
HugeInteger::operator* (const HugeInteger & a) const
{
    HugeInteger tmp;
    tmp.reserve (size () + a.size () - 1);

    size_t i, j;
    for (i = 0; i < a.size (); i++) {
        for (j = 0; j < size (); j++) {
            tmp.at (i + j) += this->at(j) * a.at(i);
        }
    }

    return tmp;
}

const HugeInteger 
HugeInteger::operator/ (const HugeInteger & a) const
{
    if (a.size () == 1 && a.at (0) == 0)
        throw exception ();

    HugeInteger tmp;
    if (size () < a.size ())
        return tmp;
    else
    {
        // lazily done here
        long long fool = this->number ();
        fool /= a.number ();
        tmp = fool;
        return tmp;
    }
}

size_t HugeInteger::length () const
{
    int tmp = 0;
    int len = 0;
    
    for (size_t i = 0; i < size (); i++) {
        tmp += (*this).at(i);
        tmp /= base;
        len++;
    }

    while (tmp)
    {
        len++;
        tmp /= base;
    }

    return len;
}

string HugeInteger::str () const
{
    long tmp = 0;
    string ret_string;

    ret_string.reserve (size ());
    
    for (size_t i = 0; i < size (); i++) {
        tmp += (*this).at(i);
        ret_string.push_back (tmp % base + '0');
        tmp /= base;
    }

    while (tmp)
    {
        ret_string.push_back (tmp % base + '0');
        tmp /= base;
    }
    
    if (ret_string.length () == 0)
        return string ("0");
    else
        return string (ret_string.rbegin (), ret_string.rend ());
}

long long HugeInteger::number () const
{
    long long tmp = 0;
    int mbase = 1;

    for (size_t i = 0; i < size (); i++) {
        tmp += (*this).at(i) * mbase;
        mbase *= base;
    }

    return tmp;
}

void HugeInteger::print (ostream & out) const
{
    out << str ();
}


int & HugeInteger::at (size_t a)
{
    return numbers[a];
}

int HugeInteger::at (size_t a) const
{
    if (a > size ())
        return 0;
    else
        return numbers[a];
}

void HugeInteger::reserve (size_t a)
{
    numbers.resize (a);
}

void HugeInteger::push_back (int a)
{
    numbers.push_back (a);
}

void HugeInteger::push_front (int a)
{
    numbers.push_front (a);
}

size_t HugeInteger::size () const
{
    return numbers.size ();
}

void HugeInteger::from_string (const char * it)
{
    for (; *it; ++it)
    {
        if (isdigit (*it))
            push_front (*it - '0');
        else
            push_front (0);
    }
}

ostream & operator<< (ostream & out, const HugeInteger & a)
{
    a.print (out);
    return out;
}

istream & operator>> (istream & in, HugeInteger & a)
{
    string tmp;
    in >> tmp;
    a = tmp;
    return in;
}
